package p.ithorns.framework.xxljob;

/**
 * XxlJobAutoRegister
 *
 * @author Ht.L
 * @date 2024-01-03 22:00
 * @since 1.0.0
 */

import com.xxl.job.core.handler.annotation.XxlJob;
import jakarta.annotation.Nonnull;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.env.Environment;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

public class XxlJobAutoRegister implements ApplicationListener<ApplicationReadyEvent> {

    // private static final Logger log = LoggerFactory.getLogger(XxlJobAutoRegister.class);

    private final ApplicationContext appCtx;

    private final Environment environment;

    private final XxlJobOperator jobOperator;

    public XxlJobAutoRegister(ApplicationContext appCtx, Environment environment, XxlJobOperator jobOperator) {
        this.appCtx = appCtx;
        this.environment = environment;
        this.jobOperator = jobOperator;
    }

    @Override
    public void onApplicationEvent(@Nonnull ApplicationReadyEvent event) {
        //注册执行器
        addJobGroup();

        //注册任务
        addJobInfo();
    }

    /**
     * 注册执行器
     */
    private void addJobGroup() {
        // 检查是否存在
        if (!jobOperator.checkIfGroupExists()) {
            jobOperator.registerJobGroup();
        }
    }

    private void addJobInfo() {
        List<XxlJobGroup> jobGroups = jobOperator.getJobGroup();
        XxlJobGroup xxlJobGroup = jobGroups.get(0);

        String[] beanDefinitionNames = appCtx.getBeanNamesForType(Object.class, false, true);
        for (String beanDefinitionName : beanDefinitionNames) {
            Object bean = appCtx.getBean(beanDefinitionName);

            Map<Method, XxlJob> annotatedMethods = MethodIntrospector.selectMethods(bean.getClass(),
                    (MethodIntrospector.MetadataLookup<XxlJob>) method -> AnnotatedElementUtils.findMergedAnnotation(method, XxlJob.class));
            for (Map.Entry<Method, XxlJob> methodXxlJobEntry : annotatedMethods.entrySet()) {
                Method executeMethod = methodXxlJobEntry.getKey();
                XxlJob xxlJob = methodXxlJobEntry.getValue();

                //自动注册
                if (executeMethod.isAnnotationPresent(XxlJobMeta.class)) {
                    XxlJobMeta xxlJobMeta = executeMethod.getAnnotation(XxlJobMeta.class);
                    XxlJobInfo xxlJobInfo = createXxlJobInfo(xxlJobGroup, xxlJob, xxlJobMeta);
                    jobOperator.initXxlJob(xxlJobInfo);
                }
            }
        }
    }

    private XxlJobInfo createXxlJobInfo(XxlJobGroup xxlJobGroup, XxlJob xxlJob, XxlJobMeta xxlJobMeta) {
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        xxlJobInfo.setJobGroup(xxlJobGroup.getId());
        xxlJobInfo.setJobDesc(xxlJobMeta.jobDesc());
        xxlJobInfo.setAuthor(xxlJobMeta.author());
        xxlJobInfo.setScheduleType("CRON");

        // 从Spring容器中获取yaml参数
        String value = environment.resolvePlaceholders(xxlJobMeta.cron());
        xxlJobInfo.setScheduleConf(value);
        xxlJobInfo.setGlueType("BEAN");
        xxlJobInfo.setExecutorHandler(xxlJob.value());
        xxlJobInfo.setExecutorRouteStrategy(xxlJobMeta.routeStrategy());
        xxlJobInfo.setMisfireStrategy("DO_NOTHING");
        xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION");
        xxlJobInfo.setExecutorTimeout(0);
        xxlJobInfo.setExecutorFailRetryCount(0);
        xxlJobInfo.setGlueRemark("GLUE代码初始化");
        xxlJobInfo.setTriggerStatus(xxlJobMeta.triggerStatus());

        return xxlJobInfo;
    }

    private void getElValue(Method method, Object[] args) {
        DefaultParameterNameDiscoverer defaultParameterNameDiscoverer = new DefaultParameterNameDiscoverer();
        // 这里参考的org.springframework.context.expression.MethodBasedEvaluationContext.lazyLoadArguments
        String[] parameterNames = defaultParameterNameDiscoverer.getParameterNames(method);
        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression("");// annotation.spel()
        StandardEvaluationContext ctx = new StandardEvaluationContext();
        // 填充表达式上下文环境
        for (int i = 0; i < parameterNames.length; i++) {
            ctx.setVariable(parameterNames[i], args[i]);
        }
        String value = expression.getValue(ctx, String.class);
    }

}